package com.googlecode.kipler.owlapi;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.semanticweb.owl.model.OWLClass;
import org.semanticweb.owl.model.OWLDataAllRestriction;
import org.semanticweb.owl.model.OWLDataExactCardinalityRestriction;
import org.semanticweb.owl.model.OWLDataMaxCardinalityRestriction;
import org.semanticweb.owl.model.OWLDataMinCardinalityRestriction;
import org.semanticweb.owl.model.OWLDataSomeRestriction;
import org.semanticweb.owl.model.OWLDataValueRestriction;
import org.semanticweb.owl.model.OWLDescription;
import org.semanticweb.owl.model.OWLDescriptionVisitor;
import org.semanticweb.owl.model.OWLIndividual;
import org.semanticweb.owl.model.OWLObjectAllRestriction;
import org.semanticweb.owl.model.OWLObjectComplementOf;
import org.semanticweb.owl.model.OWLObjectExactCardinalityRestriction;
import org.semanticweb.owl.model.OWLObjectIntersectionOf;
import org.semanticweb.owl.model.OWLObjectMaxCardinalityRestriction;
import org.semanticweb.owl.model.OWLObjectMinCardinalityRestriction;
import org.semanticweb.owl.model.OWLObjectOneOf;
import org.semanticweb.owl.model.OWLObjectPropertyExpression;
import org.semanticweb.owl.model.OWLObjectSelfRestriction;
import org.semanticweb.owl.model.OWLObjectSomeRestriction;
import org.semanticweb.owl.model.OWLObjectUnionOf;
import org.semanticweb.owl.model.OWLObjectValueRestriction;

import com.googlecode.kipler.syntax.Role;
import com.googlecode.kipler.syntax.concept.BooleanConcept;
import com.googlecode.kipler.syntax.concept.Concept;
import com.googlecode.kipler.syntax.concept.ConceptName;
import com.googlecode.kipler.syntax.concept.InequalityConstructor;
import com.googlecode.kipler.syntax.concept.Nominal;
import com.googlecode.kipler.syntax.concept.QualifiedNoRestriction;
import com.googlecode.kipler.syntax.concept.RoleQuantification;


public class OwlApiToKiplerConceptConverter implements OWLDescriptionVisitor {
	private Concept result;

	public Concept getResult() {
		return result;
	}

	private void setResult(Concept result) {
		this.result = result;
	}

	public void visit(OWLClass arg0) {
		ConceptName cn = new ConceptName(arg0.getURI().toString());
		setResult(cn);
	}

	public void visit(OWLObjectIntersectionOf arg0) {
		setResult(createBooleanConcept(BooleanConcept.Constructor.INTERSECTION,
				convertDescriptionSet(arg0.getOperands())));
	}

	public void visit(OWLObjectUnionOf arg0) {
		setResult(createBooleanConcept(BooleanConcept.Constructor.UNION,
				convertDescriptionSet(arg0.getOperands())));
	}

	private Set<Concept> convertDescriptionSet(Set<OWLDescription> operands) {
		Set<Concept> result = new HashSet<Concept>();
		for (OWLDescription desc : operands) {
			OwlApiToKiplerConceptConverter converter = new OwlApiToKiplerConceptConverter();
			desc.accept(converter);
			result.add(converter.getResult());
		}
		return result;
	}

	private BooleanConcept createBooleanConcept(
			BooleanConcept.Constructor constructor, Set<Concept> operands) {
		BooleanConcept bc = new BooleanConcept();
		bc.setConstructor(constructor);
		BooleanConcept currBc = bc;
		int count = operands.size();
		Iterator<Concept> descIter = operands.iterator();
		for (int i = count; i > 0; i--) {
			if (i != 1) {
				Concept desc = descIter.next();
				currBc.setLhs(desc);
				if (i != 2) {
					BooleanConcept rhs = new BooleanConcept();
					rhs.setConstructor(constructor);
					currBc.setRhs(rhs);
					currBc = rhs;
				}
			} else {
				Concept desc = descIter.next();
				currBc.setRhs(desc);
			}
		}
		return bc;
	}

	public void visit(OWLObjectComplementOf arg0) {
		OwlApiToKiplerConceptConverter converter = new OwlApiToKiplerConceptConverter();
		arg0.getOperand().accept(converter);
		setResult(converter.getResult().toggleNegated());
	}

	public void visit(OWLObjectSomeRestriction arg0) {
		setResult(createRoleQuantification(RoleQuantification.Constructor.SOME,
				arg0.getProperty(), arg0.getFiller()));
	}

	public void visit(OWLObjectAllRestriction arg0) {
		setResult(createRoleQuantification(RoleQuantification.Constructor.ALL,
				arg0.getProperty(), arg0.getFiller()));
	}

	private RoleQuantification createRoleQuantification(
			RoleQuantification.Constructor constructor,
			OWLObjectPropertyExpression property, OWLDescription filler) {
		OwlApiToKiplerConceptConverter converter = new OwlApiToKiplerConceptConverter();
		filler.accept(converter);
		return new RoleQuantification(constructor, convertRole(property),
				converter.getResult());
	}

	private Role convertRole(OWLObjectPropertyExpression property) {
		String roleUri;
		if (!property.isAnonymous()) {
			roleUri = property.asOWLObjectProperty().getURI().toString();
		} else {
			roleUri = property.toString();
		}
		return new Role(roleUri);
	}

	public void visit(OWLObjectValueRestriction arg0) {
		Nominal nominal = new Nominal(arg0.getValue().getURI().toString());
		RoleQuantification rq = new RoleQuantification(
				RoleQuantification.Constructor.SOME, convertRole(arg0
						.getProperty()), nominal);
		setResult(rq);
	}

	public void visit(OWLObjectMinCardinalityRestriction arg0) {
		setResult(createQualifiedNoRestriction(
				InequalityConstructor.AT_LEAST, arg0
						.getCardinality(), arg0.getProperty(), arg0.getFiller()));
	}

	public void visit(OWLObjectExactCardinalityRestriction arg0) {
		Concept atLeast = createQualifiedNoRestriction(
				InequalityConstructor.AT_LEAST, arg0
						.getCardinality(), arg0.getProperty(), arg0.getFiller());
		Concept atMost = createQualifiedNoRestriction(
				InequalityConstructor.AT_MOST, arg0
						.getCardinality(), arg0.getProperty(), arg0.getFiller());
		setResult(new BooleanConcept(BooleanConcept.Constructor.INTERSECTION,
				atLeast, atMost));
	}

	public void visit(OWLObjectMaxCardinalityRestriction arg0) {
		setResult(createQualifiedNoRestriction(
				InequalityConstructor.AT_MOST, arg0
						.getCardinality(), arg0.getProperty(), arg0.getFiller()));
	}

	private QualifiedNoRestriction createQualifiedNoRestriction(
			InequalityConstructor constructor, int n,
			OWLObjectPropertyExpression property, OWLDescription filler) {
		OwlApiToKiplerConceptConverter converter = new OwlApiToKiplerConceptConverter();
		filler.accept(converter);
		String roleUri;
		if (!property.isAnonymous()) {
			roleUri = property.asOWLObjectProperty().getURI().toString();
		} else {
			roleUri = property.toString();
		}
		return new QualifiedNoRestriction(constructor, n, new Role(roleUri),
				converter.getResult());
	}

	public void visit(OWLObjectSelfRestriction arg0) {
		// TODO Auto-generated method stub

	}

	public void visit(OWLObjectOneOf arg0) {
		Set<Concept> nominals = new HashSet<Concept>();
		for (OWLIndividual indv : arg0.getIndividuals()) {
			nominals.add(new Nominal(indv.getURI().toString()));
		}
		BooleanConcept enumeration = createBooleanConcept(
				BooleanConcept.Constructor.UNION, nominals);
		setResult(enumeration);
	}

	public void visit(OWLDataSomeRestriction arg0) {
		// TODO Auto-generated method stub
		
	}

	public void visit(OWLDataAllRestriction arg0) {
		// TODO Auto-generated method stub

	}

	public void visit(OWLDataValueRestriction arg0) {
		// TODO Auto-generated method stub

	}

	public void visit(OWLDataMinCardinalityRestriction arg0) {
		// TODO Auto-generated method stub

	}

	public void visit(OWLDataExactCardinalityRestriction arg0) {
		// TODO Auto-generated method stub

	}

	public void visit(OWLDataMaxCardinalityRestriction arg0) {
		// TODO Auto-generated method stub

	}

}
